home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 001-025 / disk_023 / ver30 / tty / intuition / ttyio.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  12KB  |  477 lines

  1. /*
  2.  * Name:    MicroEmacs
  3.  *        Amiga terminal-dependent I/O (Intuition)
  4.  *         Strategy and much code borrowed from the Lattice C
  5.  *        example in the ROM Kernel manual.
  6.  * Version:    31
  7.  * Last edit:    21-Apr-86 ...!ihnp4!seismo!ut-sally!ut-ngp!mic
  8.  * Created:    21-Apr-86 ...!ihnp4!seismo!ut-sally!ut-ngp!mic
  9.  */
  10.  
  11. /*
  12.  * Lots of includes.
  13.  */
  14.  
  15. #include <exec/types.h>
  16. #include <exec/nodes.h>
  17. #include <exec/lists.h>
  18. #include <exec/tasks.h>
  19. #include <exec/ports.h>
  20. #include <exec/io.h>
  21. #include <devices/console.h>
  22. #include <libraries/dos.h>
  23. #include <graphics/clip.h>
  24. #include <graphics/view.h>
  25. #include <graphics/rastport.h>
  26. #include <graphics/layers.h>
  27. #include <graphics/text.h>
  28. #include <intuition/intuition.h>
  29. #undef    TRUE
  30. #undef    FALSE
  31. #include "def.h"    /* includes sysdef.h */
  32.  
  33. /*
  34.  * External functions.  Declared explicitly
  35.  * to avoid problems with different compilers.
  36.  */
  37.  
  38. extern    char            *OpenLibrary();
  39. extern    int            OpenConsole();
  40. extern    struct    Window        *OpenWindow();
  41. extern    struct    MsgPort        *CreatePort();
  42. extern    struct    IOStdReq    *CreateStdIO();
  43. extern    struct    Menu        *InitEmacsMenu();
  44. extern    struct    IntuiMessage    *GetMsg();
  45. extern    LONG            AbortIO();
  46. extern    LONG            CloseDevice();
  47. extern    LONG            ReplyMsg();
  48. extern    LONG            SetMenuStrip();
  49. extern    LONG            Wait();
  50.  
  51. /*
  52.  * Terminal I/O global variables
  53.  */
  54.  
  55. #define    NIBUF    128            /* Probably excessive.        */
  56. #define    NOBUF    512            /* Not too big for 750/730.    */
  57.  
  58. unsigned char    obuf[NOBUF];        /* Output buffer        */
  59. int        nobuf;            /* # of bytes in above        */
  60. unsigned char    ibuf[NIBUF];        /* Input buffer            */
  61. int        ibufo, nibuf;        /* head, # of bytes in ibuf    */
  62. int        nrow;            /* Terminal size, rows.        */
  63. int        ncol;            /* Terminal size, columns.    */
  64. extern char    *version[];        /* Version information        */
  65.                     /*   (I cheat and use it for    */
  66.                     /*    the window title)        */
  67. /*
  68.  * Intuition global variables
  69.  */
  70.  
  71. #define WINDOWGADGETS (WINDOWSIZING | WINDOWDRAG | WINDOWDEPTH | WINDOWCLOSE)
  72.  
  73. struct NewWindow MicroEMACS = {
  74.     0,    0,            /* start position           */
  75.     640,    200,            /* width, height               */
  76.     0,    1,                 /* detail pen, block pen    */
  77.     MENUPICK | CLOSEWINDOW |    /* IDCMP flags            */
  78.     MOUSEBUTTONS | NEWSIZE,
  79.     WINDOWGADGETS | ACTIVATE,    /* window flags            */
  80.     NULL,                /* pointer to first user gadget */
  81.     NULL,                /* pointer to user checkmark    */ 
  82.     NULL,                /* title (filled in later)    */
  83.     NULL,                /* pointer to screen (none)    */
  84.     NULL,                /* pointer to superbitmap    */
  85.     360,99,639,199,            /* sizing limits min and max    */
  86.     WBENCHSCREEN            /* screen in which to open    */ 
  87. };
  88.  
  89. struct    IntuitionBase    *IntuitionBase;        /* library bases    */
  90. struct    GfxBase        *GfxBase;
  91. struct    Window        *EmacsWindow;        /* Our window        */
  92. struct    Menu        *EmacsMenu;        /* Our menu        */
  93. struct    MsgPort        *consoleWritePort;    /* I/O ports         */
  94. struct    MsgPort        *consoleReadPort;    
  95. int            intuitionMsgBit,    /* Signal bits        */
  96.             consoleMsgBit;
  97. struct    IOStdReq    *consoleWriteMsg;    /* I/O messages        */
  98. struct    IOStdReq    *consoleReadMsg;
  99. unsigned char        letter;            /* Console input buffer    */
  100. USHORT            class,            /* Intuition event    */
  101.             code,            /*   information    */
  102.             qualifier;
  103. APTR            address;
  104. SHORT            x, y;
  105.  
  106. /*
  107.  * Some definitions
  108.  */
  109.  
  110. #define INTUITION_MESSAGE ((LONG) 1 << intuitionMsgBit)
  111. #define CONSOLE_MESSAGE ((LONG) 1 << consoleMsgBit)
  112.  
  113. /*
  114.  * Open up the virtual terminal MicroEMACS communicates with.
  115.  * Set up the window, console, and menu strip.
  116.  */
  117.  
  118. extern    int    Enable_Abort;        /* Do NOT allow abort!    */
  119.  
  120. ttopen()
  121. {
  122.     Enable_Abort = 0;        /* Disable ^C         */
  123.  
  124.     GfxBase = (struct GfxBase *)
  125.         OpenLibrary("graphics.library", (LONG) 0);
  126.     if (GfxBase  == NULL)                /* Graphics lib    */
  127.         cleanup(1);
  128.  
  129.     IntuitionBase = (struct IntuitionBase *)    /* Intuition    */
  130.         OpenLibrary("intuition.library", (LONG) 0);
  131.     if (IntuitionBase == NULL)
  132.         cleanup(2);
  133.  
  134.     /* Create our window */
  135.     MicroEMACS.Title = (UBYTE *) version[0];
  136.     EmacsWindow = OpenWindow(&MicroEMACS);
  137.     if (EmacsWindow == NULL)
  138.         cleanup(2);
  139.  
  140.     /* Ports for reading and writing */
  141.     consoleWritePort = CreatePort("Emacs.con.write",(LONG) 0);
  142.     if (consoleWritePort == NULL)
  143.         cleanup(5);
  144.     consoleWriteMsg = CreateStdIO(consoleWritePort);
  145.     if (consoleWriteMsg == NULL)
  146.         cleanup(6);
  147.  
  148.     consoleReadPort = CreatePort("Emacs.con.read",(LONG) 0);
  149.     if (consoleReadPort == NULL)
  150.         cleanup(7);
  151.     consoleReadMsg = CreateStdIO(consoleReadPort);
  152.     if (consoleReadMsg == NULL)
  153.         cleanup(8);
  154.  
  155.     /* attach the console device to our window */
  156.     if (OpenConsole(consoleWriteMsg,consoleReadMsg,EmacsWindow) != 0)
  157.         cleanup(10);
  158.  
  159.     /* attach a menu strip to the window */
  160.     EmacsMenu = InitEmacsMenu();
  161.     SetMenuStrip(EmacsWindow, EmacsMenu);
  162.  
  163.     /* determine signal bit #'s    */
  164.     intuitionMsgBit = EmacsWindow->UserPort->mp_SigBit;
  165.     consoleMsgBit = consoleReadPort->mp_SigBit;
  166.  
  167.     /* initialize console read and input buffer */
  168.     QueueRead(consoleReadMsg,&letter);
  169.     nibuf = ibufo = 0;
  170.  
  171.     /* Determine initial size of virtual terminal.    */
  172.     ttsize(&nrow,&ncol);
  173.     return (0);
  174. }
  175.  
  176. /*
  177.  * Close the virtual terminal, de-allocating
  178.  * everything we have allocated.
  179.  */
  180.  
  181. ttclose()
  182. {
  183.     ttflush();
  184.     AbortIO(consoleReadMsg);
  185.     CloseDevice(consoleWriteMsg);
  186.     cleanup(0);
  187.     Enable_Abort = 1;
  188. }
  189.  
  190. /*
  191.  * Write a single character to the screen.
  192.  * Buffered for extra speed, so ttflush()
  193.  * does all the work.
  194.  */
  195.  
  196. ttputc(c)
  197. unsigned char c;
  198. {
  199.     obuf[nobuf++] = c;
  200.     if (nobuf >= NOBUF)
  201.         ttflush();
  202. }
  203.  
  204. /*
  205.  * Flush characters from the output buffer.
  206.  * Just blast it out with a console write call.
  207.  */
  208. ttflush()
  209. {
  210.     if (nobuf > 0) {
  211.         ConWrite(consoleWriteMsg, obuf, nobuf);
  212.         nobuf = 0;
  213.     }
  214. }
  215.  
  216. /*
  217.  * Input buffer management.
  218.  *
  219.  * The input buffer is a circular queue of characters
  220.  * that is updated and manipulated by the macros and
  221.  * functions below.   This allows multiple Intuition
  222.  * events (menus, console input, etc.) to be buffered
  223.  * up until Emacs asks for them.
  224.  */
  225.  
  226. #define CharsBuffered()  (nibuf > 0 )
  227. #define TypeInChar(c)  if (nibuf < (NIBUF - 1))\
  228.                 ibuf[(ibufo + nibuf++) % NIBUF] = c;
  229.  
  230. /*
  231.  * Return the next character in the input buffer.
  232.  */
  233. static GetInputChar()
  234. {
  235.     unsigned char ch;
  236.  
  237.     if (nibuf <= 0)            /* this shouldn't happen.    */
  238.         return 0;
  239.     ch = ibuf[ibufo++];
  240.     ibufo %= NIBUF;
  241.     nibuf--;
  242.     return (int) ch;
  243. }
  244.  
  245. /*
  246.  * Get a character for Emacs, without echo or
  247.  * translation.  Basically, handle Intuition
  248.  * events until we get one that signifies
  249.  * a character was typed in some way.
  250.  */
  251.  
  252. ttgetc()
  253. {
  254.     register struct    IntuiMessage *message;        /* IDCMP message */
  255.     register LONG    wakeupmask;
  256.     register int    charfound;    /* have we got a character yet?    */
  257.  
  258.  
  259.     if (CharsBuffered())        /* check input buffer        */
  260.         return GetInputChar();    /* return immediately have one    */
  261.  
  262.     charfound = FALSE;
  263.     do {
  264.         wakeupmask = Wait(INTUITION_MESSAGE|CONSOLE_MESSAGE);
  265.  
  266.         if (wakeupmask & CONSOLE_MESSAGE) {    /* Keyboard    */
  267.             GetMsg(consoleReadPort);    /* free message    */
  268.             TypeInChar(letter);        /* do this FIRST */
  269.             QueueRead(consoleReadMsg, &letter);
  270.             charfound = TRUE;
  271.         }
  272.  
  273.         if (wakeupmask & INTUITION_MESSAGE) {    /* Intuition    */
  274.             while(message =    GetMsg(EmacsWindow->UserPort)) {
  275.                 class =    message->Class;
  276.                 code = message->Code;
  277.                 qualifier = message->Qualifier;
  278.                 address = message->IAddress;
  279.                 x = message->MouseX;
  280.                 y = message->MouseY;
  281.  
  282.                 ReplyMsg(message);
  283.                 /* Need ||= here because next event may */
  284.                 /* not result in a character... */
  285.                 charfound = charfound || HandleEvent();
  286.             } /* while (GetMsg()) */
  287.         } /* if Intuition event */
  288.     } while (charfound == FALSE);
  289.  
  290.     return GetInputChar();        /* finally got a character.    */
  291. }
  292.  
  293. /*
  294.  * Handle the events we handle...
  295.  * The result indicates if we've
  296.  * put a character in the input buffer.
  297.  * All the event information is global,
  298.  * because there's a lot of it...
  299.  */
  300.  
  301. extern    int    quit();                /* Defined by "main.c"    */
  302.  
  303. static HandleEvent()
  304. {
  305.     switch(class) {
  306.     case MENUPICK:                /* fake the menu key    */
  307.         if (code != MENUNULL)
  308.             return (DoMenu());
  309.         else
  310.             return (FALSE);        /* No character found    */
  311.         break;
  312.     case MOUSEBUTTONS:            /* fake the mouse key */
  313.         return (DoMouse());
  314.         break;
  315.         case CLOSEWINDOW:            /* Call quit() directly    */
  316.         quit(FALSE, 1, KRANDOM);    /* This loses if in a     */
  317.         return (FALSE);            /*   dialogue...    */
  318.                 break;
  319.     }
  320.     return(FALSE);                /* No char found    */
  321. }
  322.  
  323. /*
  324.  * Handle a menu selection by hand-crafting
  325.  * an escape sequence that looks like a function
  326.  * key to the terminal driver.  Save the
  327.  * menu number and item number until the
  328.  * menu execution function can ask for it.
  329.  */
  330.  
  331. int    LastMenuNum;        /* Menu number for KMENU `key'        */
  332. int    LastItemNum;        /* Menu item for KMENU `key'        */
  333. int    LastSubItem;        /* Subitem number (for completeness)    */
  334.  
  335. #define    CSI    0x9b        /* Amiga command sequence introducer    */
  336.  
  337. static DoMenu()
  338. {
  339.     struct    MenuItem *item, *ItemAddress();
  340.  
  341.     while (code != MENUNULL) {
  342.         item = ItemAddress(EmacsMenu,(LONG) code);
  343.         LastMenuNum = MENUNUM(code);    /* number of menu    */
  344.         LastItemNum = ITEMNUM(code);    /* item number        */
  345.         LastSubItem = SUBNUM(code);    /* subitem code        */
  346.         code = item->NextSelect;
  347.     }
  348.     TypeInChar(CSI);            /* fake the MENU key    */
  349.     TypeInChar('M');
  350.     TypeInChar('~');
  351.     return (TRUE);                /* found a character!    */
  352. }
  353.  
  354. /*
  355.  * Return the last menu selection numbers to
  356.  * the caller.  Used by "ttymenu.c".
  357.  */
  358.  
  359. ttmenu(menu,item,subitem)
  360. int *menu, *item, *subitem;
  361. {
  362.     *menu = LastMenuNum;
  363.     *item = LastItemNum;
  364.     *subitem = LastSubItem;
  365.     LastMenuNum = (USHORT)-1;    /* Forget the values        */
  366.     LastItemNum = (USHORT)-1;    /* so they don't get re-used    */
  367.     LastSubItem = (USHORT)-1;
  368. }
  369.  
  370.  
  371. /*
  372.  * Handle a mouse selection by inserting
  373.  * a "MOUSE key" (teer) sequence into the
  374.  * input buffer and saving the x, y and
  375.  * qualifier values for later.
  376.  */
  377.  
  378. SHORT    LastMouseX, LastMouseY;    /* Position of mouse            */
  379. USHORT    LastQualifier;        /* Qualifier (shift key?)        */
  380.  
  381. static DoMouse()
  382. {
  383.     /* Save last mouse position */
  384.     if (code != SELECTDOWN)
  385.         return (FALSE);
  386.     LastMouseX = x - EmacsWindow->BorderLeft;
  387.     LastMouseY = y - EmacsWindow->BorderTop;
  388.     LastQualifier = qualifier;
  389.  
  390.     TypeInChar(CSI);            /* fake the MOUSE key    */
  391.     TypeInChar('P');            /* P for Pointer    */
  392.     TypeInChar('~');
  393.     return (TRUE);                /* found a character!    */
  394. }
  395.  
  396. /*
  397.  * Return the last mouse click values to
  398.  * the caller.   X and Y are translated
  399.  * so that (0,0) is at the edge of the
  400.  * top and left borders. Used by "ttymouse.c".
  401.  */
  402.  
  403. ttmouse(x,y,qualifier)
  404. SHORT *x, *y;
  405. USHORT *qualifier;
  406. {
  407.     *x = LastMouseX;
  408.     *y = LastMouseY;
  409.     *qualifier = LastQualifier;
  410.     LastMouseX = (SHORT)-1;
  411.     LastMouseY = (SHORT)-1;
  412.     LastQualifier = (USHORT)-1;
  413. }
  414.  
  415. /*
  416.  * Return the current size of the virtual
  417.  * terminal to the caller.  Placed in
  418.  * ttyio.c because it uses information
  419.  * that is only available to the virtual
  420.  * terminal handler.
  421.  *
  422.  * Assumes the WorkBench screen default
  423.  * font is TOPAZ_EIGHTY (8 wide by 8 high).
  424.  */
  425.  
  426. ttsize(rows,cols)
  427. int *rows, *cols;
  428. {
  429.     *rows = (EmacsWindow->Height -         /* have to take borders    */
  430.          EmacsWindow->BorderTop -    /* into account.    */
  431.          EmacsWindow->BorderBottom) / 8;
  432.     *cols = (EmacsWindow->Width -
  433.          EmacsWindow->BorderLeft -
  434.          EmacsWindow->BorderRight) / 8;
  435. }
  436.  
  437. /*
  438.  * Clean up.
  439.  * Fall through all the possible cases (0 means
  440.  * get rid of everything and start with the case
  441.  * that fits the error situation.
  442.  */
  443.  
  444. extern    LONG    ClearMenuStrip();
  445. extern    LONG    DeleteStdIO();
  446. extern    LONG    DeletePort();
  447. extern    LONG    CloseWindow();
  448. extern    LONG    CloseLibrary();
  449.  
  450. static cleanup(prob)
  451. {
  452.     
  453.     switch (prob) {
  454.     case 0:
  455.         ClearMenuStrip(EmacsWindow);
  456.         DisposeMenus(EmacsMenu);
  457.     case 10:
  458.     case 8:
  459.         DeleteStdIO(consoleReadMsg);
  460.     case 7:
  461.         DeletePort(consoleReadPort);
  462.     case 6:
  463.         DeleteStdIO(consoleWriteMsg);
  464.     case 5:
  465.         DeletePort(consoleWritePort);
  466.     case 4:
  467.         CloseWindow(EmacsWindow);
  468.     case 2:
  469.         if (GfxBase != NULL) CloseLibrary(GfxBase);
  470.     case 1:
  471.         if (IntuitionBase != NULL) CloseLibrary(IntuitionBase);
  472.         break;
  473.     }
  474.         return(0);
  475. }
  476.  
  477.